package org.example.javachatroom.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.javachatroom.component.OnlineUserManager;
import org.example.javachatroom.mapper.MessageMapper;
import org.example.javachatroom.mapper.MessageSessionMapper;
import org.example.javachatroom.model.Friend;
import org.example.javachatroom.model.Message;
import org.example.javachatroom.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.List;

@Component
public class WebSocketController extends TextWebSocketHandler {
    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private MessageSessionMapper messageSessionMapper;

    @Autowired
    private MessageMapper messageMapper;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("[WebSocketController] 连接成功！");
        //此处API返回的是一个Map
        User user = (User) session.getAttributes().get("user");
        if(user == null){
            return;
        }
        System.out.println("获取到的userId："+user.getUserId());
        //把键值对存起来
        onlineUserManager.online(user.getUserId(),session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        System.out.println("[WebSocketController] 收到消息！"+message.toString());
       //1、先获取到当前用户的信息，后续要进行消息转发啥的
        User user = (User) session.getAttributes().get("user");
        if(user == null){
            System.out.println("[WebSocketController] user == null! 未登录用户，无法进行消息转发");
            return;
        }
        //2、针对请求进行解析把json字符串，转成java对象
        MessageRequest request = objectMapper.readValue(message.getPayload(), MessageRequest.class);
        if(request.getType().equals("message")){
            //进行消息转发
            transferMessage(user,request);
        }else{
            System.out.println("[WebSocketAPI] request.type有误！"+message.getPayload());
        }
    }
    //通过这个方法完成消息转发
    //第一个参数表示这个要转发的消息是从谁哪里来的
    private void transferMessage(User fromuser, MessageRequest request) throws IOException {
        //1、先构造一个转发的响应对象，MessageResponse
        MessageResponse resp = new MessageResponse();
        resp.setType("message");    //这里不设置也行，默认就是message
        resp.setFromId(fromuser.getUserId());
        resp.setFromName(fromuser.getUsername());
        resp.setSessionId(request.getSessionId());
        resp.setContent(request.getContent());
        //把这个java对象转换成json字符串
        String respjson = objectMapper.writeValueAsString(resp);
        System.out.println("[transferMessage] respjson"+respjson);
        //2、根据请求中的sessionId,获取到这个MessageSession里都有哪些用户，通过查询数据库就可以知道了
        List<Friend> friends = messageSessionMapper.getFriendBySessionId(request.getSessionId(), fromuser.getUserId());
        //此处注意：上述数据库查询会把发送人自己排除掉，而我们发送消息需要给自己也发一份
        //把当前用户也添加到上述List里面
        Friend myself  = new Friend();
        myself.setFriendId(fromuser.getUserId());
        myself.setFriendName(fromuser.getUsername());
        friends.add(myself);

        //3、循环遍历上述的这个列表，给列表中的每个用户都发一份响应消息
        //  注意：这里出了给查询到的好友们发，也要给自己发一个，方便实现在自己的客户端上显示自己发送的消息
        //  注意：一个会话中，可能有多个用户（群聊），虽然客户端是没有支持群聊的（前端写起来相对麻烦）
        //  后端无论是API和数据库都是支持群聊的
        for(Friend friend:friends){
            //  知道了每个用户的userId,进一步查询刚才准备好的OnlineUserManager，就知道了对应的WebSocketSession
            //  从而进行发送消息
            WebSocketSession webSocketSession = onlineUserManager.getSession(friend.getFriendId());
            if(webSocketSession == null){
                //如果用户未在线，就先不发送
                continue;
            }
            webSocketSession.sendMessage(new TextMessage(respjson));
        }
        //4、转发的消息需要放到数据库里，后续用户如果下线之后，重新上线，还可以通过历史消息的方式来拿到之前的消息
        //需要往message表里插入一条记录
        Message message = new Message();
        message.setFromId(fromuser.getUserId());
        message.setSessionId(request.getSessionId());
        message.setContent(request.getContent());
        //像自增主键，还有时间这样的属性，直接用sql让数据库生成即可
        messageMapper.add(message);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("[WebSocketController] 连接异常！"+exception.toString());
        User user = (User) session.getAttributes().get("user");
        if(user == null){
            return;
        }
        onlineUserManager.offline(user.getUserId(),session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.out.println("[WebSocketController] 连接关闭！"+status.toString());
        User user = (User) session.getAttributes().get("user");
        if(user == null){
            return;
        }
        onlineUserManager.offline(user.getUserId(),session);

    }
}
